package com.zaicheng.cloud.remotecallclient;

import com.zaicheng.cloud.Client;
import com.zaicheng.cloud.RemoteCallContext;
import com.zaicheng.cloud.remotecall.ReflectiveRemoteCall;
import com.zaicheng.cloud.remotecall.ReflectiveRemoteCall.RemoteCallInvocationHandler;
import com.zaicheng.cloud.remotecall.RemoteCall;
import com.zaicheng.cloud.remotecall.Target;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.StringUtils;

import java.lang.reflect.Proxy;

/**
 @author zaicheng
 @version 1.0
 @date 2022-04-19
 @email zzc15847256473@163.com
 */


public class RemoteCallClientFactoryBean implements FactoryBean<Object>, InitializingBean, ApplicationContextAware {

    private Class<?> type;

    private String name;

    private String value;

    private  String url;

    private  String path;

    private String contextId;

    private  ApplicationContext applicationContext;

    private Class<?> fallBack;

    private  Class<?> fallBackFactory;


    // 改造这里
    @Override
    public Object getObject() throws Exception {
        return this.getTarget();
    }

    <T> T  getTarget(){

        RemoteCallContext remoteCallContext = this.applicationContext.getBean(RemoteCallContext.class);

        RemoteCall.Builder  builder  =  this.remoteCall(remoteCallContext);

        if (!StringUtils.hasText(this.url)){

            if (!name.startsWith("http")){
                this.url = "http://" + this.name;
            }else {
                this.url = this.name;
            }
            this.url = this.url + this.cleanPath();

            return (T) this.loadBalance(builder,remoteCallContext, new Target.RemoteCallTarget<>(this.type,this.name,this.url));
        }else {

            if (StringUtils.hasText(this.url) && !this.url.startsWith("http")){
                this.url = "http://" + this.url;
            }
            String url = this.url + this.cleanPath();
        }
        return  null;
    }

    private <T> T  get(RemoteCallContext context,Class<T> type){
        T instance = context.getInstance(this.contextId, type);
        if (instance == null){
            throw  new IllegalStateException("对于这个上下文："+this.contextId+",没有找到类型对应的bean");
        }else{
            return instance;
        }
    }

    private <T> T loadBalance(RemoteCall.Builder builder, RemoteCallContext remoteCallContext, Target.RemoteCallTarget<T> target) {
        Client optional = this.getOptional(remoteCallContext, Client.class);
        if (optional != null){
            builder.client(optional);
            Targeter targeter = this.get(remoteCallContext, Targeter.class);
            return targeter.target(this,builder,remoteCallContext,target);
        }else {
            throw new IllegalStateException("没有负载均衡客户端被定义，您引入对应的依赖了吗?");
        }
    }

    private <T> T getOptional(RemoteCallContext remoteCallContext, Class<Client> clientClass) {
        return (T) remoteCallContext.getInstance(this.contextId,clientClass);
    }

    private RemoteCall.Builder remoteCall(RemoteCallContext remoteCallContext) {
        return  new RemoteCall.Builder();
    }

    private String cleanPath() {
        String path = this.path.trim();
        if (StringUtils.hasLength(path)){
            if (!path.startsWith("/")){
                path = "/" + path;
            }
            if (path.endsWith("/")){
                path = path.substring(0,path.length()-1);
            }
        }
        return  path;
    }


    @Override
    public Class<?> getObjectType() {
        return this.type;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("初始化完成.....");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.applicationContext = applicationContext;
    }

    public Class<?> getType() {
        return this.type;
    }



    public void setType(Class<?> type) {
        this.type = type;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getValue() {
        return this.value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public String getUrl() {
        return this.url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getPath() {
        return this.path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public String getContextId() {
        return this.contextId;
    }

    public void setContextId(String contextId) {
        this.contextId = contextId;
    }

    public ApplicationContext getApplicationContext() {
        return this.applicationContext;
    }

    public Class<?> getFallBack() {
        return fallBack;
    }

    public void setFallBack(Class<?> fallBack) {
        this.fallBack = fallBack;
    }

    public Class<?> getFallBackFactory() {
        return fallBackFactory;
    }

    public void setFallBackFactory(Class<?> fallBackFactory) {
        this.fallBackFactory = fallBackFactory;
    }
}
